<template>
  <div class="package-graph">
    <el-card class="chart-card">
      <template #header>
        <div class="card-header">
          <div class="header-left">
            <h3>🔗 包依赖关系图</h3>
            <p class="header-subtitle">工作空间包之间的依赖关系可视化</p>
          </div>
          <div class="header-actions">
            <el-tooltip content="选择布局方式" placement="top">
              <el-select
                v-model="layoutType"
                size="small"
                style="width: 100px; margin-right: 8px;"
                @change="refreshChart"
              >
                <el-option label="环形" value="circular" />
                <el-option label="力导向" value="force" />
                <el-option label="固定" value="none" />
              </el-select>
            </el-tooltip>

            <el-tooltip
              :content="showRootPackage ? '隐藏根包' : '显示根包'"
              placement="top"
            >
              <el-button
                :type="showRootPackage ? 'primary' : 'default'"
                size="small"
                @click="toggleShowRootPackage"
              >
                {{ showRootPackage ? '隐藏根包' : '显示根包' }}
              </el-button>
            </el-tooltip>
          </div>
        </div>
      </template>

      <div v-if="loading" class="loading-container">
        <el-skeleton :rows="5" animated />
      </div>

      <div v-else-if="graphData" class="chart-container">
        <v-chart
          ref="chartRef"
          class="chart"
          :option="chartOption"
          @click="onChartClick"
          autoresize
        />
      </div>

      <div v-else class="empty-container">
        <el-empty description="暂无包依赖关系数据" />
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, type Ref } from 'vue';
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { GraphChart } from 'echarts/charts';
import {
  TitleComponent,
  TooltipComponent,
  LegendComponent,
} from 'echarts/components';
import VChart from 'vue-echarts';
import { AnalysisDataService } from '../services/analysis-data';

// 注册 ECharts 组件
use([
  CanvasRenderer,
  GraphChart,
  TitleComponent,
  TooltipComponent,
  LegendComponent,
]);

/**
 * 包依赖关系图数据接口
 */
interface IPackageGraphData {
  nodes: Array<{
    id: string;
    name: string;
    type: string;
    value: number;
    category: number;
    itemStyle?: any;
  }>;
  links: Array<{
    source: string;
    target: string;
    value: number;
    lineStyle?: any;
  }>;
  categories: Array<{ name: string }>;
}

// 响应式数据
const loading: Ref<boolean> = ref(true);
const graphData: Ref<IPackageGraphData | null> = ref(null);
const chartRef = ref<InstanceType<typeof VChart> | null>(null);
const showRootPackage: Ref<boolean> = ref(false); // 控制是否显示根包
const layoutType: Ref<'force' | 'circular' | 'none'> = ref('circular'); // 布局类型
const analysisService = AnalysisDataService.getInstance();

/**
 * 图表配置选项
 */
const chartOption = computed(() => {
  if (!graphData.value) return {};

  // 为“按节点隐藏”提供图例：将每个节点映射为独立图例项
  const nodeLegendItems = graphData.value.nodes.map(n => n.name);

  // 为每个节点分配按类型上色，且将 category 设为该节点在图例中的索引，以便 legend 控制
  const colorMap: Record<string, string> = {
    workspace: '#73C0DE',
    root: '#FAC858',
  };

  const seriesData = graphData.value.nodes.map((n, idx) => ({
    ...n,
    category: idx,
    itemStyle: {
      color: n.itemStyle?.color ?? colorMap[n.type] ?? '#91CC75',
      ...n.itemStyle,
    }
  }));

  // 图例类别与 series.category 对齐
  const categories = nodeLegendItems.map(name => ({ name }));

  return {
    title: {
      text: '工作空间包依赖关系',
      subtext: `共 ${graphData.value.nodes.length} 个包，${graphData.value.links.length} 个依赖关系（点击节点或图例可隐藏/显示节点）`,
      left: 'center',
      top: 10,
      textStyle: {
        fontSize: 16,
        fontWeight: 'bold',
        color: '#303133'
      },
      subtextStyle: {
        fontSize: 12,
        color: '#909399'
      }
    },
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(50, 50, 50, 0.95)',
      borderColor: '#409EFF',
      borderWidth: 1,
      textStyle: {
        color: '#fff',
        fontSize: 12
      },
      formatter: (params: any) => {
        if (params.dataType === 'node') {
          const typeText = params.data.type === 'workspace' ? '工作空间包' : '根包';
          return `
            <div style="padding: 8px;">
              <div style="font-weight: bold; margin-bottom: 6px; color: #409EFF;">${params.data.name}</div>
              <div style="margin-bottom: 3px;">📦 类型：${typeText}</div>
              <div>📄 文件数：${params.data.value}</div>
            </div>
          `;
        } else {
          return `
            <div style="padding: 8px;">
              <div style="font-weight: bold; margin-bottom: 6px; color: #E6A23C;">依赖关系</div>
              <div style="margin-bottom: 3px;">🔗 ${params.data.source}</div>
              <div style="text-align: center; margin: 4px 0; color: #67C23A;">⬇️</div>
              <div>📦 ${params.data.target}</div>
            </div>
          `;
        }
      },
    },
    legend: [
      {
        type: 'scroll',
        data: nodeLegendItems,
        selectedMode: 'multiple',
        orient: 'horizontal',
        bottom: 10,
        itemGap: 18,
        textStyle: {
          fontSize: 12,
          color: '#606266'
        },
        icon: 'roundRect',
        pageIconColor: '#409EFF',
        pageIconInactiveColor: '#C0C4CC'
      },
    ],
    animationDurationUpdate: 2000,
    animationEasingUpdate: 'quinticInOut' as any,
    series: [
      {
        name: '包依赖关系',
        type: 'graph',
        layout: layoutType.value,
        circular: layoutType.value === 'circular' ? {
          rotateLabel: true
        } : undefined,
        force: layoutType.value === 'force' ? {
          repulsion: [150, 300],
          gravity: 0.05,
          edgeLength: [80, 200],
          layoutAnimation: true,
        } : undefined,
        data: seriesData,
        links: graphData.value.links,
        categories,
        roam: true,
        draggable: true,
        focusNodeAdjacency: true,
        label: {
          show: true,
          position: 'right',
          formatter: (params: any) => {
            // 简化包名显示
            let name = params.data.name;

            // 如果是 @gct/ 开头的包，只显示后面的部分
            if (name.startsWith('@gct/')) {
              name = name.substring(5);
            }

            // 如果名称过长，截断并添加省略号
            return name.length > 15
              ? name.substring(0, 12) + '...'
              : name;
          },
          fontSize: 11,
          fontWeight: 'bold',
          color: '#303133',
          backgroundColor: 'rgba(255, 255, 255, 0.95)',
          padding: [4, 8],
          borderRadius: 6,
          borderWidth: 1,
          borderColor: '#E4E7ED',
          shadowBlur: 4,
          shadowColor: 'rgba(0, 0, 0, 0.1)',
        },
        labelLayout: {
          hideOverlap: true,
          moveOverlap: 'shiftY',
        },
        scaleLimit: {
          min: 0.4,
          max: 2.5,
        },
        lineStyle: {
          color: '#409EFF',
          width: 2,
          opacity: 0.6,
          curveness: 0.1, // 减少弯曲度，让线条更直
          type: 'solid',
        },
        emphasis: {
          focus: 'adjacency',
          scale: 1.2,
          label: {
            fontSize: 13,
            fontWeight: 'bold',
            backgroundColor: 'rgba(255, 255, 255, 1)',
            borderColor: '#409EFF',
            color: '#409EFF',
          },
          lineStyle: {
            width: 4,
            opacity: 1,
            shadowBlur: 10,
            shadowColor: '#409EFF',
          },
        },
        itemStyle: {
          borderColor: '#fff',
          borderWidth: 3,
          shadowBlur: 8,
          shadowColor: 'rgba(0, 0, 0, 0.2)',
        },
        symbolSize: (value: number) => {
          // 根据文件数量动态调整节点大小，但保持合理范围
          const size = Math.max(30, Math.min(80, value * 4 + 20));
          return size;
        },
      },
    ],
  };
});

/**
 * 加载包依赖关系图数据
 */
const loadGraphData = async (): Promise<void> => {
  try {
    loading.value = true;

    // 检查是否已有数据
    let currentData = analysisService.getCurrentAnalysisData();

    if (!currentData) {
      // 加载数据（路径从环境变量获取）
      await analysisService.loadAnalysisData();
    }

    // 获取包依赖关系图数据，默认不包含根包
    const graph = analysisService.getPackageDependencyGraph(showRootPackage.value);
    graphData.value = graph;
  } catch (error) {
    console.error('加载包依赖关系图数据失败:', error);
  } finally {
    loading.value = false;
  }
};

/**
 * 切换是否显示根包
 */
const toggleShowRootPackage = async (): Promise<void> => {
  showRootPackage.value = !showRootPackage.value;
  await loadGraphData();
};

/**
 * 刷新图表（布局变更时）
 */
const refreshChart = (): void => {
  // 触发图表重新渲染，通过改变数据引用来实现
  if (graphData.value) {
    graphData.value = { ...graphData.value };
  }
};

/**
 * 点击节点时切换该节点的图例选择，从而隐藏/显示该节点
 */
const onChartClick = (params: any): void => {
  if (!params || params.dataType !== 'node') return;
  const nodeName: string = params.data?.name;
  if (!nodeName) return;

  const instance = (chartRef.value as any)?.getEchartsInstance?.();
  if (!instance) return;

  const opt: any = instance.getOption();
  const legend = Array.isArray(opt.legend) ? opt.legend[0] : opt.legend;
  const selectedMap = legend?.selected || {};
  const currentlySelected = selectedMap[nodeName] !== false; // 未定义视为已选

  instance.dispatchAction({
    type: currentlySelected ? 'legendUnSelect' : 'legendSelect',
    name: nodeName
  });
};

// 组件挂载时加载数据
onMounted(() => {
  loadGraphData();
});
</script>

<style scoped>
.package-graph {
  margin-bottom: 20px;
}

.chart-card {
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.header-left h3 {
  margin: 0 0 8px 0;
  color: #303133;
  font-size: 18px;
  font-weight: 600;
}

.header-subtitle {
  margin: 0;
  color: #909399;
  font-size: 14px;
  line-height: 1.4;
}

.header-actions {
  display: flex;
  gap: 8px;
}

.loading-container {
  padding: 20px;
}

.chart-container {
  padding: 20px;
  height: 600px; /* 增加高度 */
}

.chart {
  width: 100%;
  height: 100%;
}

.empty-container {
  padding: 40px;
  text-align: center;
}
</style>
